﻿using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using NUnit.Framework;

namespace Drill.Configuration
{
	[TestFixture]
	public class DependencyResolverConfigurationExceptionTests
	{
		[Category("UnitTest")]
		[Test]
		public void CanConstructWithNoParameters()
		{
			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException();

			Assert.That(dependencyResolverException, Is.Not.Null);
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithMessageParameter()
		{
			const string message = "This is a test message.";

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(message);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.Message, Is.EqualTo(message));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithMessageAndInnerExceptionParameters()
		{
			const string message = "This is a test message.";

			Exception innerException = new Exception("This is an inner exception.");

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(message, innerException);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.Message, Is.EqualTo(message));
			Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithMessageAndArg0Parameters()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value.";
			const string message = "This is a formatted test message with {0}.";
			const string arg0 = "arg0Value";

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(message, arg0);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithMessageArg0AndArg1Parameters()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value and arg1Value.";
			const string message = "This is a formatted test message with {0} and {1}.";
			const string arg0 = "arg0Value";
			const string arg1 = "arg1Value";

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(message, arg0, arg1);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithMessageArg0Arg1AndArg2Parameters()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value and arg2Value.";
			const string message = "This is a formatted test message with {0}, {1} and {2}.";
			const string arg0 = "arg0Value";
			const string arg1 = "arg1Value";
			const string arg2 = "arg2Value";

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(message, arg0, arg1, arg2);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithMessageAndArgsParametersWithFourArgParamItems()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
			const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
			const string arg0 = "arg0Value";
			const string arg1 = "arg1Value";
			const string arg2 = "arg2Value";
			const string arg3 = "arg3Value";

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(message, arg0, arg1, arg2, arg3);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithMessageAndArgsParametersWithFourArgParamItemsAsArray()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
			const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
			const string arg0 = "arg0Value";
			const string arg1 = "arg1Value";
			const string arg2 = "arg2Value";
			const string arg3 = "arg3Value";

			string[] args = new[] { arg0, arg1, arg2, arg3 };

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(message, args);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithInnerExceptionAndMessageParameters()
		{
			const string message = "This is a test message.";

			Exception innerException = new Exception("This is an inner exception.");

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(innerException, message);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
			Assert.That(dependencyResolverException.Message, Is.EqualTo(message));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithInnerExceptionMessageAndArg0Parameters()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value.";
			const string message = "This is a formatted test message with {0}.";
			const string arg0 = "arg0Value";

			Exception innerException = new Exception("This is an inner exception.");

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(innerException, message, arg0);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithInnerExceptionMessageArg0AndArg1Parameters()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value and arg1Value.";
			const string message = "This is a formatted test message with {0} and {1}.";
			const string arg0 = "arg0Value";
			const string arg1 = "arg1Value";

			Exception innerException = new Exception("This is an inner exception.");

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(innerException, message, arg0, arg1);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithInnerExceptionMessageArg0Arg1AndArg2Parameters()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value and arg2Value.";
			const string message = "This is a formatted test message with {0}, {1} and {2}.";
			const string arg0 = "arg0Value";
			const string arg1 = "arg1Value";
			const string arg2 = "arg2Value";

			Exception innerException = new Exception("This is an inner exception.");

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(innerException, message, arg0, arg1, arg2);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithInnerExceptionMessageAndArgsParametersWithFourArgParamItems()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
			const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
			const string arg0 = "arg0Value";
			const string arg1 = "arg1Value";
			const string arg2 = "arg2Value";
			const string arg3 = "arg3Value";

			Exception innerException = new Exception("This is an inner exception.");

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(innerException, message, arg0, arg1, arg2, arg3);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructWithInnerExceptionMessageAndArgsParametersWithFourArgParamItemsAsArray()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
			const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
			const string arg0 = "arg0Value";
			const string arg1 = "arg1Value";
			const string arg2 = "arg2Value";
			const string arg3 = "arg3Value";

			string[] args = new[] { arg0, arg1, arg2, arg3 };

			Exception innerException = new Exception("This is an inner exception.");

			DependencyResolverConfigurationException dependencyResolverException = new DependencyResolverConfigurationException(innerException, message, args);

			Assert.That(dependencyResolverException, Is.Not.Null);
			Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
			Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
		}

		[Category("UnitTest")]
		[Test]
		public void CanConstructUsingDeserializationConstructor()
		{
			const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
			const string expectedInnerExceptionMessage = "This is an inner exception.";
			const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
			const string arg0 = "arg0Value";
			const string arg1 = "arg1Value";
			const string arg2 = "arg2Value";
			const string arg3 = "arg3Value";

			string[] args = new[] { arg0, arg1, arg2, arg3 };

			Exception innerException = new Exception(expectedInnerExceptionMessage);

			DependencyResolverConfigurationException dependencyResolverException1 = new DependencyResolverConfigurationException(innerException, message, args);

			// Serialize the dependency services exception into binary format.
			byte[] binaryData;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				BinaryFormatter formatter = new BinaryFormatter();
				formatter.Serialize(memoryStream, dependencyResolverException1);

				binaryData = new byte[memoryStream.Length];
				memoryStream.Position = 0;
				memoryStream.Read(binaryData, 0, binaryData.Length);
				memoryStream.Close();
			}

			// Deserialize the binary data (serialized dependency services exception).
			DependencyResolverConfigurationException dependencyResolverException2;
			using (MemoryStream memoryStream = new MemoryStream(binaryData))
			{
				BinaryFormatter formatter = new BinaryFormatter();
				dependencyResolverException2 = (DependencyResolverConfigurationException)formatter.Deserialize(memoryStream);
			}

			Assert.That(dependencyResolverException2, Is.Not.Null);
			Assert.That(dependencyResolverException2.InnerException, Is.Not.Null);
			Assert.That(dependencyResolverException2.InnerException.Message, Is.EqualTo(expectedInnerExceptionMessage));
			Assert.That(dependencyResolverException2.Message, Is.EqualTo(expectedFormattedMessage));
		}
	}
}